package com.csii.activiti.server.core.listener;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.csii.activiti.server.abstraction.constant.MessageType;
import com.csii.activiti.server.abstraction.entity.*;
import com.csii.activiti.server.abstraction.service.ActMessageService;
import com.csii.activiti.server.abstraction.service.ActUserService;
import com.csii.activiti.server.core.constant.ApprovalConfigConstant;
import com.csii.activiti.server.core.constant.CommonConstant;
import com.csii.activiti.server.core.constant.FlowNodeTypeConstant;
import com.csii.activiti.server.core.entity.ActFlowCache;
import com.csii.activiti.server.core.entity.ActFlowNode;
import com.csii.activiti.server.core.entity.db.ActFlowPublishConfigEntity;
import com.csii.activiti.server.core.entity.db.ActFlowTaskIdAndCommentEntity;
import com.csii.activiti.server.core.mapper.ActExtensionMapper;
import com.csii.activiti.server.core.mapper.ActFlowNodeMapper;
import com.csii.activiti.server.core.mapper.ActFlowPublishConfigurationMapper;
import com.csii.activiti.server.core.service.FlowCallbackManagementService;
import com.csii.activiti.server.core.service.FlowVariableService;
import com.csii.activiti.server.core.utils.ELUtils;
import com.github.benmanes.caffeine.cache.Cache;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.delegate.event.ActivitiEvent;
import org.activiti.engine.delegate.event.ActivitiEventListener;
import org.activiti.engine.delegate.event.ActivitiEventType;
import org.activiti.engine.delegate.event.impl.ActivitiActivityEventImpl;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.ExecutionEntityImpl;
import org.activiti.engine.impl.persistence.entity.VariableInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.Serializable;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Slf4j
@Component
public class AuditorGlobalListener implements ActivitiEventListener,Serializable{
    private static final long serialVersionUID = 1L;

    @Autowired
    private ActFlowNodeMapper actFlowNodeMapper;

    @Autowired
    private ActUserService actUserService;

    @Autowired
    private RuntimeService runtimeService;


    @Autowired
    private ActMessageService actMessageService;

    @Autowired
    private ActExtensionMapper actExtensionMapper;

    @Autowired
    private FlowCallbackManagementService flowCallbackManagementService;

    @Autowired
    private ActFlowPublishConfigurationMapper actFlowPublishConfigurationMapper;

    @Autowired
    private RepositoryService repositoryService;

    @Resource(name = "caffeineCache")
    private Cache<String,Object> cache;


    @Autowired
    private FlowVariableService flowVariableService;



    private Pattern regex = Pattern.compile("\\$\\{([^}]*)\\}");

    private final String PREFIX_INSTANCE_CONTEXT = "instanceContext.";

    private final String PREFIX_FORM_DATA = "formData.";

    private final String INITIATOR = "initiator";
    private final String PROCESS_INSTANCE_ID = "processInstanceId.";
    private final String PROCESS_NAME = "processName";
    private final String LEFT_SYMBOL = "${";
    private final String RIGHT_SYMBOL = "}";


    @Override
    public void onEvent(ActivitiEvent event) {
        ActivitiActivityEventImpl activityEvent;
        if (ActivitiEventType.ACTIVITY_STARTED.equals(event.getType()) && "userTask".equals((activityEvent = (ActivitiActivityEventImpl) event).getActivityType()) && cache.getIfPresent(event.getProcessInstanceId()+((ActivitiActivityEventImpl) event).getActivityId()) == null){
            String activityId = activityEvent.getActivityId();
            ActFlowNode actFlowNode = actFlowNodeMapper.selectById(activityId).transitionActFlowNode();
            HashSet<String> users = new HashSet<>();
            ExecutionEntityImpl processInstance = getExecutionEntityImpl();
            if (processInstance != null && processInstance.getName() == null){
                //设置流程名称
                runtimeService.setProcessInstanceName(processInstance.getProcessInstanceId(), processInstance.getProcessDefinitionName());
            }
            boolean isSendMessage = true;
            if (FlowNodeTypeConstant.MESSAGE_NODE.equals(actFlowNode.getNodeType())){
                users.add(CommonConstant.MESSAGE_PREFIX_KEY + actFlowNode.getMessageKey());
                isSendMessage = false;
            }else{
                users.addAll(getApproveUsernames(actFlowNode, activityEvent.getProcessInstanceId(), activityEvent.getExecutionId(),processInstance));
            }
            ActFlowCache actFlowCache = new ActFlowCache();
            if (!users.isEmpty()){
                //设置审批人
                runtimeService.setVariable(activityEvent.getExecutionId(), ApprovalConfigConstant.COUNTERSIGN_FLOW_VARIABLE_KEY,users);
                //合并节点
                boolean mergeAdjacentNodes = actFlowNode.getConfigurationItem().isMergeAdjacentNodes();
                Set<String> cloneUsers = (Set<String>) users.clone();
                if (mergeAdjacentNodes) {
                    actFlowCache.setMergeAdjacentNodes(true);
                    Set<String> taskIds;
                    List<ActFlowTaskIdAndCommentEntity> commentList = null;
                    if (CollUtil.isNotEmpty(taskIds = actExtensionMapper.queryLastApproveTaskIds(event.getProcessInstanceId())) && CollUtil.isNotEmpty(commentList = actExtensionMapper.queryFlowCommentsByTaskIds(taskIds, null, "comment"))){
                        Set<String> lastUsers = commentList.stream().map(ActFlowTaskIdAndCommentEntity::getUserId).collect(Collectors.toSet());
                        actFlowCache.setLastUsers(lastUsers);
                        cloneUsers.removeAll(lastUsers);
                    }

                }

                //如果是过滤发起人
                if (actFlowNode.getConfigurationItem().isOriginatorSameFilter()){
                    //设置true
                    actFlowCache.setOriginatorSameFilter(true);
                    //过滤掉不需要发待办
                    if (cloneUsers.contains(processInstance.getStartUserId())){
                        cloneUsers.remove(processInstance.getStartUserId());
                    }
                }
                cloneUsers = cloneUsers.stream().filter(item-> !item.equals(ApprovalConfigConstant.AUTO_BYPASS) && !item.equals(ApprovalConfigConstant.AUTO_REJECTED)).collect(Collectors.toSet());
                //发送消息
                if (isSendMessage && !cloneUsers.isEmpty()){
                    ActSendMessage sendMessage = new ActSendMessage();
                    sendMessage.setTenantId(processInstance.getTenantId());
                    sendMessage.setCurrentNodeId(activityId);
                    sendMessage.setCurrentNodeName(activityEvent.getActivityName());
                    sendMessage.setProcessDefinitionId(processInstance.getProcessDefinitionId());
                    sendMessage.setProcessInstanceId(processInstance.getProcessInstanceId());
                    sendMessage.setProcessName(processInstance.getName() == null ? processInstance.getProcessDefinitionName() : processInstance.getName());
                    sendMessage.setProcessKey(processInstance.getProcessDefinitionKey());
                    if (processInstance.getProcessDefinitionKey() == null && processInstance.getProcessDefinitionId() != null){
                        sendMessage.setProcessKey(processInstance.getProcessDefinitionId().split(":")[0]);
                    }
                    sendMessage.setInitiator(processInstance.getStartUserId());
                    Map<String, Object> formData = (Map<String, Object>) processInstance.getVariableInstance(CommonConstant.FORM_DATA).getValue();
                    sendMessage.setFormData(formData);
                    VariableInstance callbackVariableInstance = processInstance.getVariableInstance(CommonConstant.REMOTE_URL);
                    if (callbackVariableInstance != null){
                        sendMessage.setCallbackList((List<ActFlowRemoteCallback>) callbackVariableInstance.getValue());
                    }
                    sendMessage.setCurrentDate(new Date());
                    String deploymentId = repositoryService.createProcessDefinitionQuery().processDefinitionId(processInstance.getProcessDefinitionId()).singleResult().getDeploymentId();
                    ActFlowPublishConfigEntity flowPublish = actFlowPublishConfigurationMapper.selectOne(new LambdaQueryWrapper<ActFlowPublishConfigEntity>().select(ActFlowPublishConfigEntity::getId, ActFlowPublishConfigEntity::getIconType,ActFlowPublishConfigEntity::getSummary,ActFlowPublishConfigEntity::getManyConditionJson).eq(ActFlowPublishConfigEntity::getId, deploymentId));
                    if (flowPublish != null){
                        sendMessage.setIconType(flowPublish.getIconType());
                        sendMessage.setSummary(ELUtils.getSummary(flowPublish.getSummary(),flowPublish.getManyConditionJson(),formData));
                    }
                    List<ActReceivedBy> receivedByList = cloneUsers.stream().map(username -> new ActReceivedBy(processInstance.getProcessInstanceId(), username)).collect(Collectors.toList());
                    sendMessage.setReceivedByList(receivedByList);
                    actMessageService.sendMessage(sendMessage, MessageType.todo);
                    //触发回调
                    flowCallbackManagementService.callback(sendMessage,MessageType.todo.getType());
                }
            }
            cache.put(event.getProcessInstanceId()+activityId,actFlowCache);
        }
    }


    private ExecutionEntityImpl getExecutionEntityImpl(){
        CommandContext commandContext = Context.getCommandContext();
        Collection<ExecutionEntity> involvedExecutions = commandContext.getInvolvedExecutions();
        Iterator<ExecutionEntity> iterator = involvedExecutions.iterator();
        ExecutionEntityImpl executionEntity = (ExecutionEntityImpl) iterator.next();
        ExecutionEntityImpl processInstance = executionEntity.getProcessInstance();
        return processInstance;
    }


    public Set<String> getApproveUsernames(ActFlowNode actFlowNode,String processInstanceId,String executionId,ExecutionEntityImpl processInstance){
        List<ActUser> approvers = new ArrayList<>();
        Set<String> users  =  new HashSet<>();
        if (processInstance == null){
            processInstance = getExecutionEntityImpl();
        }
        if (actFlowNode.getApprovers() != null){
            //审批人处理
            approvers = actFlowNode.getApprovers();
        }else if (actFlowNode.getApproverRole() != null){
            //角色处理
            approvers = actUserService.queryUserByRoleCode(actFlowNode.getApproverRole().getRoleCode());
            if (!FlowNodeTypeConstant.PEOPLE_WHO_COPIED.equals(actFlowNode.getNodeType()) && CollUtil.isEmpty(approvers)){
                if (ApprovalConfigConstant.AUTO_BYPASS.equals(actFlowNode.getConfigurationItem().getApprovalIsEmpty())) {
                    approvers = CollUtil.newArrayList(new ActUser(ApprovalConfigConstant.AUTO_BYPASS,"系统自动审批"));
                }else if (ApprovalConfigConstant.AUTO_REJECTED.equals(actFlowNode.getConfigurationItem().getApprovalIsEmpty())){
                    approvers = CollUtil.newArrayList(new ActUser(ApprovalConfigConstant.AUTO_REJECTED,"系统自动审批"));
                }else{
                    //为空就覆盖指定的人
                    approvers = actFlowNode.getConfigurationItem().getStandbyApprover();
                }
            }
        }else if(StrUtil.isNotBlank(actFlowNode.getVariable())){
            Set<String> usernames = flowVariableService.queryVariableApprovalUsername(actFlowNode.getVariable(), actFlowNode, executionId, processInstance);

            if (CollUtil.isEmpty(usernames)){
                if (ApprovalConfigConstant.AUTO_BYPASS.equals(actFlowNode.getConfigurationItem().getApprovalIsEmpty())) {
                    approvers = CollUtil.newArrayList(new ActUser(ApprovalConfigConstant.AUTO_BYPASS,"系统自动审批"));
                }else if (ApprovalConfigConstant.AUTO_REJECTED.equals(actFlowNode.getConfigurationItem().getApprovalIsEmpty())){
                    approvers = CollUtil.newArrayList(new ActUser(ApprovalConfigConstant.AUTO_REJECTED,"系统自动审批"));
                }else{
                    //为空就覆盖指定的人
                    approvers = actFlowNode.getConfigurationItem().getStandbyApprover();
                }
            }else{
                users.addAll(usernames);
            }
//            //变量
//            if (FlowNodeVariableTypeConstant.lead.equals(actFlowNode.getVariable())) {
//                //发起人领导
//                String username = processInstance.getStartUserId();
//                List<ActUser> actUsers = actUserService.queryHisLeadershipByUsername(username);
//                if (CollUtil.isEmpty(actUsers)){
//                    if (ApprovalConfigConstant.AUTO_BYPASS.equals(actFlowNode.getConfigurationItem().getApprovalIsEmpty())) {
//                        approvers = CollUtil.newArrayList(new ActUser(ApprovalConfigConstant.AUTO_BYPASS,"系统自动审批"));
//                    }else if (ApprovalConfigConstant.AUTO_REJECTED.equals(actFlowNode.getConfigurationItem().getApprovalIsEmpty())){
//                        approvers = CollUtil.newArrayList(new ActUser(ApprovalConfigConstant.AUTO_REJECTED,"系统自动审批"));
//                    }else{
//                        //为空就覆盖指定的人
//                        approvers = actFlowNode.getConfigurationItem().getStandbyApprover();
//                    }
//                }else{
//                    approvers.addAll(actUsers);
//                }
//            }else if (FlowNodeVariableTypeConstant.oneself.equals(actFlowNode.getVariable())) {
//                //发起人自己
//                String username = processInstance.getStartUserId();
//                users.add(username);
//            }else if (FlowNodeVariableTypeConstant.optional.equals(actFlowNode.getVariable())) {
//                //发起自选
//                Map variable = runtimeService.getVariable(executionId, CommonConstant.FORM_DATA, Map.class);
//                List<String> optionalUsers = (List<String>) variable.get(actFlowNode.getVariableValue());
//                users.addAll(optionalUsers);
//            }
        }else if (actFlowNode.getThirdPartyUrl() != null) {
            //第三方
            Map variable = runtimeService.getVariable(executionId, CommonConstant.FORM_DATA, Map.class);
            Map<String, String> instanceContext = new HashMap<>();
            instanceContext.put(INITIATOR,processInstance.getStartUserId());
            instanceContext.put(PROCESS_INSTANCE_ID,processInstance.getProcessInstanceId());
            instanceContext.put(PROCESS_NAME,processInstance.getProcessDefinitionName());
            String url = actFlowNode.getThirdPartyUrl();
            Matcher matcher = regex.matcher(actFlowNode.getThirdPartyUrl());
            //使用正则提取参数
            while (matcher.find()) {
                //参数替换
                String param = matcher.group(1);
                if (param.startsWith(PREFIX_INSTANCE_CONTEXT)){
                    String value = instanceContext.get(param.replace(PREFIX_INSTANCE_CONTEXT,""));
                    if (value != null){
                        url = url.replace(LEFT_SYMBOL + param + RIGHT_SYMBOL, value);
                    }
                }else{
                    if (param.startsWith(PREFIX_FORM_DATA)){
                        param = param.replace(PREFIX_FORM_DATA,"");
                    }
                    Object value = variable.get(param);
                    if (value != null) {
                        url = url.replace(LEFT_SYMBOL + param + RIGHT_SYMBOL, value.toString());
                    }
                }


            }

            try {
                String usernamesStr = HttpUtil.get(url);
                List<String> usernames = JSONObject.parseArray(usernamesStr, String.class);
                users.addAll(usernames);
            } catch (Exception e) {
                log.info("第三方获取用户异常:{}", e);
            }
            //如果获取不到人员就是用备用方案
            if (!FlowNodeTypeConstant.PEOPLE_WHO_COPIED.equals(actFlowNode.getNodeType()) && users.isEmpty()) {
                if (ApprovalConfigConstant.AUTO_BYPASS.equals(actFlowNode.getConfigurationItem().getApprovalIsEmpty())) {
                    approvers = CollUtil.newArrayList(new ActUser(ApprovalConfigConstant.AUTO_BYPASS, "系统自动审批"));
                } else if (ApprovalConfigConstant.AUTO_REJECTED.equals(actFlowNode.getConfigurationItem().getApprovalIsEmpty())) {
                    approvers = CollUtil.newArrayList(new ActUser(ApprovalConfigConstant.AUTO_REJECTED, "系统自动审批"));
                } else {
                    //为空就覆盖指定的人
                    approvers = actFlowNode.getConfigurationItem().getStandbyApprover();
                }
            }
        }
        if (!approvers.isEmpty()){
            users.addAll(approvers.stream().map(ActUser::getUsername).collect(Collectors.toList()));
        }

        return users;
    }

    @Override
    public boolean isFailOnException() {
        return false;
    }

}
